﻿module poseidon.style.dstyle;

private import poseidon.style.stylekeeper;

class DStyle : AbstractStyleKeeper
{
	private import std.utf;
	private import poseidon.globals;
	private import dwt.extra.scintilla;
	private import poseidon.controller.scintillaex;
	private import poseidon.controller.gui;
	private import Analyzer.D.syntax.nodeHsu;
	private import poseidon.intellisense.search;
	private import std.string;

	/+
	enum
	{
		SCE_D_DEFAULT = 0,
		SCE_D_COMMENT = 1,
		SCE_D_COMMENTLINE = 2,
		SCE_D_COMMENTDOC = 3,
		SCE_D_COMMENTNESTED = 4,
		SCE_D_NUMBER = 5,
		SCE_D_WORD = 6,
		SCE_D_WORD2 = 7,
		SCE_D_WORD3 = 8,
		SCE_D_TYPEDEF = 9,
		SCE_D_STRING = 10,
		SCE_D_STRINGEOL = 11,
		SCE_D_CHARACTER = 12,
		SCE_D_OPERATOR = 13,
		SCE_D_IDENTIFIER = 14,
		SCE_D_COMMENTLINEDOC = 15,
		SCE_D_COMMENTDOCKEYWORD = 16,
		SCE_D_COMMENTDOCKEYWORDERROR = 17,
	}
	+/
	enum 
	{
		SCE_D_DEFAULT = 0
		,SCE_D_COMMENT = 1
		,SCE_D_COMMENTLINE = 2
		,SCE_D_COMMENTDOC = 3
		,SCE_D_NUMBER = 4
		,SCE_D_WORD = 5
		,SCE_D_STRING = 6
		,SCE_D_CHARACTER = 7
		,SCE_D_UUID = 8
		,SCE_D_PREPROCESSOR = 9
		,SCE_D_OPERATOR = 10
		,SCE_D_IDENTIFIER = 11
		,SCE_D_STRINGEOL = 12
		,SCE_D_VERBATIM = 13
		,SCE_D_REGEX = 14
		,SCE_D_COMMENTLINEDOC = 15
		,SCE_D_WORD2 = 16
		,SCE_D_VERBATIMTICK = 17
		,SCE_D_COMMENTDOCKEYWORDERROR = 18
		,SCE_D_GLOBALCLASS = 19
		,SCE_D_WORD3 = 20
		,SCE_D_WORD4 = 21
		,SCE_D_WORD5 = 22
		,SCE_D_WORD6 = 23
		,SCE_D_WORD7 = 24
		,SCE_D_WORD8 = 25
		,SCE_D_WORD9 = 26
		,SCE_D_NESTCOMMENT = 27
		,SCE_D_NESTCOMMENT1 = 28
		,SCE_D_NESTCOMMENT2 = 29
		,SCE_D_NESTCOMMENT3 = 30
		,SCE_D_NESTCOMMENT4 = 31
	}

	const int SCLEX_D = 76;
	//const int SCLEX_D = 79;
	
	// the default key words
	const static char[][] sKeyWords = 
	["void bit byte ubyte short ushort int uint long ulong cent ucent float double real ifloat idouble ireal cfloat cdouble creal char wchar dchar body asm bool true false function delegate"
	, "public private protected with extern"
	, "final abstract override const debug version pragma public private deprecated protected volatile"
	, "class struct interface enum new this null delete invariant super union"
	, "if for foreach while do assert return unittest try catch else throw switch case break continue default finally goto synchronized"
	, "is import module alias typedef with cast package typeof typeid"
	, "in out const static inout ref lazy extern export auto align scope"
	];


	const char[] LEXER_NAME = "SCLEX_D";
	char[] getLexerName() { return LEXER_NAME;}
	int getLexerID() { return SCLEX_D; }
	
	char[][] getKeyWords()
	{
		if(keyWords is null)
			keyWords = sKeyWords.dup;
		return keyWords; 
	}

	void applySettings(ScintillaEx sc) 
	{
		// check whether keywords and styles loaded successfully,
		// make sure styles is not null
		getStyles();
		getKeyWords();
		
		super.applySettings(sc);
		
		// do extra d settings here

		// !!! notify handle should only install once
		Object obj = sc.getData("Handler-set");
		if(obj is null) 
		{
			sc.setData("handler-set", "true");
			sc.handleNotify(sc, Scintilla.SCN_UPDATEUI, &onUpdateUI);
			sc.handleNotify(sc, Scintilla.SCN_AUTOCSELECTION, &onAutoCSelection);
			sc.handleNotify(sc, Scintilla.SCN_CHARADDED, &onCharAdded);
		}
	}

	void resetKeyWords()
	{
		keyWords = sKeyWords.dup;
	}
	
	void onUpdateUI( SCNotifyEvent event )
	{
		Scintilla sc = cast(Scintilla) event.cData;
		
		if ( sc.getStyleAt( sc.getCurrentPos() ) == SCE_D_STRING || sc.getStyleAt( sc.getCurrentPos() ) == SCE_D_STRINGEOL )
		{} 
		else performWordHover( sc );
	}

	// 加入mruParser
	private void onAutoCSelection( SCNotifyEvent e )
	{
		Scintilla sc = cast(Scintilla) e.cData;

		CAnalyzerTreeNode[] treeNodes = sAutoComplete.search( e.text );
		
		if( treeNodes.length ) 
		{
			foreach( CAnalyzerTreeNode t; treeNodes )
			{
				if( t.identifier == e.text )
				{
					sAutoComplete.mruParser.addItem( e.text.dup );
					break;
				}
			}
		}
	}

	// 鍵入字的時候
	private void onCharAdded( SCNotifyEvent e ) 
	{
		if( !Globals.useCodeCompletion ) return;
		
		ScintillaEx sc = cast(ScintillaEx) e.cData;
		int ch = e.ch;

		try
		{
			if( ch == '.' ) 
			{
				/+
				CAnalyzerTreeNode t = searchFunctionHead( sc );
				if( t )
					sGUI.toolMan.txtFunctionHead.setText( t.typeIdentifier ~ " " ~ t.identifier ~ "(" ~ t.parameterString ~ ")" );
				else
					sGUI.toolMan.txtFunctionHead.setText( null );
				+/
				
				performDotCompletionAndFunctionToolTip( sc, false );
			}
			else if( ch == '(' )
			{
				performDotCompletionAndFunctionToolTip( sc, true );
			}
			else if( ch == ' ')
			{
				char[] word = readCurrentWord( sc, true );
				if( word == "import" )
					performImportStart( sc );
				else 
					performAbbreviationExpand(sc);
			}else
			{
				if( Globals.updateParseLive ) addAnalyzerNodeLive( sc );
			}
		
			performAutoComplete( sc );
		}
		catch( Exception e )
		{
			if( !sc ) 
				MessageBox.showMessage( "ScintillaEx Error!!" );
			else
				MessageBox.showMessage( e.toString );
		}
	}

	static void performAutoComplete( ScintillaEx sc, bool forceComplete = false )
	{
		char[] word = readCurrentWord( sc );

		if ( word.length >= 2 )
		{
			if( forceComplete ) sc.autoCCancel();
			if( sc.autoCActive() ) return;

			//sc.autoCSetSeparator( ' ' );

			char[] list;
			if( forceComplete ) 
				list = sAutoComplete.forceComplete( word );
			else
			{
				CAnalyzerTreeNode headNode = searchFunctionHead( sc );//findFunctionHead( sc );
				list = sAutoComplete.autoCSearch( word, headNode );
			}

			if( list.length ) sc.autoCShow( word.length, list );
		}
	}

	private void performDotCompletionAndFunctionToolTip( Scintilla sc, bool bFunctionToolTip )
	{
		char[][] currentWords = readCurrentWholeWord( sc );

		if( !currentWords.length ) return;
	
		CAnalyzerTreeNode functionHeadNode = searchFunctionHead( sc );

		char[]	list, listToolTip;
		performAnalyzer( currentWords, functionHeadNode, list, listToolTip, bFunctionToolTip );

		if( bFunctionToolTip )
		{
			if( listToolTip.length )
			{
				listToolTip = listToolTip[0..$-1]; // strip off last newline

				Rectangle rectEditorScreen = sGUI.editor.getBounds(); // get editor width
				int marginWidth = sc.getMarginWidthN( 0 ) + sc.getMarginWidthN( 1 ) + sc.getMarginWidthN( 2 );
				int screenWidth = rectEditorScreen.width - marginWidth;
				int currentX = sc.pointXFromPosition( sc.getCurrentPos() );
				int currentY = sc.pointYFromPosition( sc.getCurrentPos() );
				int callTipX = currentX;
				int tipsTextLength = 0, tipsMaxWidth = -1;

				char[][] tips = std.string.split( listToolTip, "\n" );
				if( tips.length > 1 )
				{
					foreach( char[] s; tips )
					{
						if( s.length > tipsTextLength ) 
						{
							tipsTextLength = s.length;
							tipsMaxWidth = sc.textWidth( sc.STYLE_DEFAULT, s );
						}
					}
				}
				
				if( sc.getVScrollBar() ) screenWidth -= 30;

				// Nested Function
				void _insertChangeLine( inout char[] texts, in int listToolTipWidth )
				{
					char[] tempText;
					
					int lineWidth = screenWidth / sc.textWidth( sc.STYLE_DEFAULT, " " );

					if( lineWidth <= 2 )
					{
						texts.length = 0;
						return;
					}

					for( int i = 0; i < texts.length; ++ i )
					{
						if( i > 0 )
							if( i % lineWidth == 0 ) tempText ~= "\n";

						tempText ~= texts[i];
					}

					texts =  tempText;
				}

				listToolTip.length = 0;
				bool bMaxWidth;
				
				foreach( char[] s; tips )
				{
					int listWidth = sc.textWidth( sc.STYLE_DEFAULT, s );

					if( tipsMaxWidth > 0 )
					{
						if( listWidth > screenWidth )
						{
							if( !bMaxWidth )
							{
								if( listWidth >= tipsMaxWidth )
								{
									callTipX = marginWidth;
									bMaxWidth = true;
								}
							}
									
							_insertChangeLine( s, tipsMaxWidth );
						}
						else if( listWidth > screenWidth - currentX )
						{
							if( !bMaxWidth )
							{
								if( listWidth >= tipsMaxWidth )
								{
									callTipX = screenWidth + marginWidth - listWidth;
									bMaxWidth = true;
								}
							}							
						}
					}
					else
					{
						if( listWidth > screenWidth )
						{
							callTipX = marginWidth;
							_insertChangeLine( s, listWidth );
						}
						else if( listWidth > screenWidth - currentX )
						{
							callTipX = screenWidth + marginWidth - listWidth;
						}
					}

					listToolTip ~= ( s ~ "\n" );
				}

				sc.callTipSetBack( 0xffffff );
				sc.callTipSetFore( 0x777777 );
				sc.callTipShow( sc.positionFromPoint( callTipX, currentY ), listToolTip[0..length - 1] );
			}
		}
		else
		{
			if ( !list.length )
			{
				char[] word = readImportWord( sc );
				word = word.replace( ".", "\\" );
				word.strip();
				// TODO: Array out of bounds
				try
				{
					if( word[--$] == '\\' )
					{ 
						word = word[0..$-1];
						//MessageBox.showMsg(word);
					}
					list = sAutoComplete.importParser.autoCSearch(word);
				}
				catch( Exception e )
				{
					Util.trace( e.toString() );
				}
			}

			if( list.length ) sc.autoCShow( 0, list );
		}
		
	}

	
	private CAnalyzerTreeNode performAnalyzer( char[][] currentWords, CAnalyzerTreeNode functionHeadNode, 
												inout char[] list, inout char[] listToolTip, bool bFunctionToolTip )
	{
		bool 				bIsArray, bIsFunction, bIsTemplateFunction, bNotFriendClass;
		char[]				word;
		CAnalyzerTreeNode 	activeTreeNode;
		CAnalyzerTreeNode[] baseClasses;
		
		if( !sAutoComplete.fileParser ) return null;
		if( !currentWords.length ) return null;

		// Nested Function
		char[] _checkArrayOrFunction( char[] str )
		{
			if( !str.length ) return null;


			char[][] splitedWords = std.string.split( str, "!" );
			if( splitedWords.length > 1 )
			{
				bIsArray = false;
				bIsFunction = false;
				bIsTemplateFunction = true;
			}
			else
			{
				splitedWords = std.string.split( str, "(" );
				if( splitedWords.length > 1 )
				{
					bIsArray = false;
					bIsFunction = true;
					bIsTemplateFunction = false;
				}
				else
				{
					splitedWords = std.string.split( str, "[" );
					if( splitedWords.length > 1 )
					{
						bIsArray = true;
						bIsFunction = false;
						bIsTemplateFunction = false;
					}
				}
			}

			return splitedWords[0];

			/+
			char[][] splitedWords = std.string.split( str, "[" );
			if( splitedWords.length > 1 )
			{
				bIsArray = true;
				bIsFunction = false;
			}
			else
			{
				bIsArray = false;
				splitedWords = std.string.split( str, "(" );
				if( splitedWords.length > 1 ) bIsFunction = true;else bIsFunction = false;
			}

			if( bIsFunction )
			{
				char[][] splitedTemplateWords = std.string.split( splitedWords[0], "!" );
				if( splitedTemplateWords.length > 1 )
				{
					bIsFunction = false;
					bIsTemplateFunction = true;
				}
				else
					bIsTemplateFunction = false;

				return splitedTemplateWords[0];
			}
			return splitedWords[0];
			+/
		}

		void _checkAlias( inout char[] aWord, CAnalyzerTreeNode node )
		{
			// 反向找尋D_ALIAS
			CAnalyzerTreeNode typeAlias = sAutoComplete.getAnalyzerTreeNode( aWord, D_ALIAS | D_TYPEDEF, node, true );
			if( !typeAlias )
			{
				CAnalyzerTreeNode[] dummyAnalyzers;
				typeAlias = sAutoComplete.getImport( aWord, D_ALIAS | D_TYPEDEF, node, dummyAnalyzers );
			}
			if( typeAlias ) aWord = typeAlias.typeIdentifier;
		}
		
		CAnalyzerTreeNode _getType( CAnalyzerTreeNode treeNode )
		{
			if( treeNode )
			{
				if( treeNode.DType == D_FUNCTION )
				{
					CAnalyzerTreeNode _getReturnType()
					{
						char[] lookup0 = treeNode.typeIdentifier;

						_checkAlias( lookup0, treeNode );

						if( lookup0.length ) lookup0 = std.string.removechars( lookup0, "*" );

						if( lookup0 != "void" )
						{
							if( !isBuiltInType( lookup0, list ) )
							{
								char[][] 	splitedTypeIdentifier = std.string.split( lookup0, "[" );
								char[] 		lookup = splitedTypeIdentifier[0];

								// we check to see if the return type of the function is a UDT
								CAnalyzerTreeNode type = sAutoComplete.getAnalyzerTreeNode( lookup, D_UDTS, treeNode );
								if( !type )
								{
									CAnalyzerTreeNode[] dummyAnalyzers;
									type = sAutoComplete.getImport( lookup, D_UDTS, treeNode, dummyAnalyzers  );
									bNotFriendClass = true;
								}
								if( type )
								{
									if( splitedTypeIdentifier.length > 1 )
										isBuiltInType( "char[]", list );
									else
										list = symbolsToAutoCShow( type, bNotFriendClass, baseClasses );

									return type;
								}
							}
						}

						return null;
 					}


					if( !bIsFunction )
					{
						if( bFunctionToolTip )
						{
							CAnalyzerTreeNode father = treeNode.getRoot();
							char[] oriIdentifier = treeNode.identifier;

							if( father )
							{
								foreach( CAnalyzerTreeNode t; father.getAllLeaf() )
								{
									if( t.identifier == oriIdentifier )
										listToolTip ~= ( t.typeIdentifier ~ " " ~ t.identifier ~ "(" ~ t.parameterString ~ ")\n" );
								}
							}
						}
						else
							if( !treeNode.parameterString.length ) return _getReturnType();
					}
					else
						return _getReturnType();
				}
				else if( treeNode.DType & D_UDTS )
				{
					if( treeNode.DType & D_TEMPLATE )
					{
						if( !bIsTemplateFunction ) 
						{
							if( treeNode.getLeafCount() == 1 )
							{
								if( treeNode.getLeaf( 0 ).identifier == treeNode.identifier )
								{
									if( treeNode.getLeaf( 0 ).DType & D_FUNCTION ) return _getType( treeNode.getLeaf( 0 ) );
								}
								else
									return null;
							}
							else
								return null;
						}
						else
						{
							if( treeNode.getLeafCount() == 1 )
							{
								if( treeNode.getLeaf( 0 ).identifier == treeNode.identifier )
								{
									if( treeNode.getLeaf( 0 ).DType & ( D_CLASS | D_INTERFACE | D_STRUCT ) ) treeNode = treeNode.getLeaf( 0 );
								}
							}
						}
					}
					else if( treeNode.DType & D_ENUM )
					{
						char[][] enumWords;
						
						list = " min?21 max?21 sizeof?21";

						foreach( CAnalyzerTreeNode t; treeNode.getAllLeaf() )
							enumWords ~= ( t.identifier ~ "?25" );

						scope CCharsSort!( char[] ) sortList = new CCharsSort!( char[] )( enumWords );
						enumWords = sortList.pop();
						list = std.string.join( enumWords, " " ) ~ list;

						return null;
					}

					if( treeNode.baseClass.length ) baseClasses = sAutoComplete.getBaseClassNode( treeNode );


					if( bFunctionToolTip )
					{
						if( treeNode )
						{
							if( treeNode.DType & D_CLASS )
							{
								foreach( CAnalyzerTreeNode t; treeNode.getAllLeaf() )
								{
									if( t.DType & D_CTOR )
										listToolTip ~= ( t.identifier ~ "(" ~ t.parameterString ~ ")\n" );
								}
								//return null;
							}
							else if( treeNode.DType & D_STRUCT )
							{
								foreach( CAnalyzerTreeNode t; treeNode.getAllLeaf() )
								{
									if( t.DType & D_FUNCTION )
										if( t.identifier == "opCall" )
											listToolTip ~= ( t.identifier ~ "(" ~ t.parameterString ~ ")\n" );
								}
							}
							else if( treeNode.DType & D_TEMPLATE )
							{
								listToolTip ~= ( treeNode.identifier ~ "(" ~ treeNode.parameterString ~ ")\n" );
							}
						}
					}
				
					list = symbolsToAutoCShow( treeNode, bNotFriendClass, baseClasses );
					return treeNode;
					
				}
				else if( treeNode.DType == D_VARIABLE || treeNode.DType == D_PARAMETER )
				{
					char[] 	lookup = treeNode.typeIdentifier;
					int 	DType = D_CLASS | D_INTERFACE | D_STRUCT | D_UNION;

					//if( bIsFunction ) return null;

					//找尋D_ALIAS
					_checkAlias( lookup, treeNode );
					
					if( !isBuiltInType( lookup, list ) )
					{
						char[][] templateType = std.string.split( lookup, "!" );

						if( templateType.length > 1 ) // 變數TYPE含有!
						{
							DType = DType | D_TEMPLATE;
							lookup = templateType[0];
						}
						else
						{
							char[][] tempLookup = std.string.split( lookup, "[" );

							if( tempLookup.length > 1 ) // 變數TYPE含有[]
							{
								if( bIsArray )
									lookup = tempLookup[0];
								else
								{
									lookup = null;
									isBuiltInType( "char[]", list );
								}
							}
						}


						if( lookup.length ) lookup = std.string.removechars( lookup, "*" );
						
						// 先從此檔案的Parser反向找起
						CAnalyzerTreeNode type = sAutoComplete.getAnalyzerTreeNode( lookup, DType, treeNode );
						if( !type )
						{
							CAnalyzerTreeNode[] dummyAnalyzers;
							CAnalyzerTreeNode tt = sAutoComplete.getImport( lookup, DType, treeNode, dummyAnalyzers );
							type = tt;
							bNotFriendClass = true;
						}
						
						// For Template
						if( type ) 
						{
							if( type.DType & D_TEMPLATE )
							{
								CAnalyzerTreeNode _findTemplateMemberNode( CAnalyzerTreeNode node, char[] ident )
								{
									foreach( CAnalyzerTreeNode t; node.getAllLeaf() )
									{
										if( t.identifier == ident )
											if( t.DType & ( D_CLASS | D_INTERFACE | D_STRUCT | D_FUNCTION ) ) return t;
									}									
								}
								
								if( type.getLeafCount() == 1 )
								{
									if( type.getLeaf( 0 ).identifier == type.identifier )
									{
										if( type.getLeaf( 0 ).DType & ( D_CLASS | D_INTERFACE | D_STRUCT ) ) type = type.getLeaf( 0 );
									}
								}

								
								char[] 	templateWord;
								int		countParen;

								foreach( char c; treeNode.typeIdentifier )
								{
									if( c == '!' || c == '*' || c == '[' || c == ']' )
										continue;
									else if( c == '(' )
										countParen ++;
									else if( c == ')' )
										countParen --;
									else
									{
										if( countParen == 0 ) templateWord ~= c;
									}
								}

								char[][] splitTemplateWords = std.string.split( templateWord, "." );

								if( splitTemplateWords.length > 1 )
								{
									for( int i = 1; i < splitTemplateWords.length; ++ i )
									{
										type = _findTemplateMemberNode( type, splitTemplateWords[i] );
									}
								}
							}

							// 取得繼承class
							if( type.baseClass.length ) baseClasses = sAutoComplete.getBaseClassNode( type );

							list = symbolsToAutoCShow( type, bNotFriendClass, baseClasses );
							return type;
						}
						else
						{
							char[][] splitTypeIdents = std.string.split( lookup, "." );
							if( splitTypeIdents.length )
							{
								char[] _list, _listToolTip;
								CAnalyzerTreeNode typeTreeNode = performAnalyzer( splitTypeIdents, treeNode, _list, _listToolTip, bFunctionToolTip );
								if( typeTreeNode !is null )
								{
									if( typeTreeNode.baseClass.length ) baseClasses = sAutoComplete.getBaseClassNode( typeTreeNode );
									list = symbolsToAutoCShow( typeTreeNode, bNotFriendClass, baseClasses );
									listToolTip = _listToolTip;
									//MessageBox.showMessage( "ffff" );
									return typeTreeNode;
								}
							}
						}
					}
					else
					{
						char[][] tempLookup = std.string.split( lookup, "[" );
						if( bIsArray && tempLookup.length == 1 ) list = null;
					}
				}
			}

			return null;
		}

		CAnalyzerTreeNode _lookBLOCK( CAnalyzerTreeNode treeNode )
		{
			if( !treeNode ) return activeTreeNode;
			if( activeTreeNode ) return activeTreeNode;

			foreach( CAnalyzerTreeNode t; treeNode.getAllLeaf() )
			{
				/+
				version( Windows )
				{
					if( t.DType & D_VERSION )
					{
						if( t.identifier == "Windows" || t.identifier == "Win32" )
						{
							activeTreeNode = sAutoComplete.getMemberAnalyzerTreeNode( word, D_ALL - D_BLOCK, t, baseClasses );
							baseClasses.length = 0;
						}

						if( activeTreeNode ) return activeTreeNode;
					}
				}
				+/

				
				if( t.DType == D_BLOCK )
				{
					activeTreeNode = sAutoComplete.getMemberAnalyzerTreeNode( word, D_ALL - D_BLOCK, t, baseClasses );
					baseClasses.length = 0;
					
					if( activeTreeNode )
						return activeTreeNode;
					else
						_lookBLOCK( t );
				}
				if( activeTreeNode ) break;;
			}

			return activeTreeNode;
		}


		CAnalyzerTreeNode[] _getRenamedImport()
		{
			if( !functionHeadNode ) return null;
			
			CAnalyzerTreeNode[] imports;
			
			// Nested Function
			void _lookingFormNode( CAnalyzerTreeNode treeNode )
			{
				CAnalyzerTreeNode rootNode = treeNode.getRoot();
				
				if( rootNode )
				{
					foreach( CAnalyzerTreeNode t; rootNode.getAllLeaf() )
					{
						if( t.DType & D_IMPORT ) imports ~= t;
					}

					_lookingFormNode( rootNode );
				}
			}

			_lookingFormNode( functionHeadNode );

			return imports;
		}		


		CAnalyzerTreeNode[] importModules;
		bool				bModuleImportCall;

		CAnalyzerTreeNode _judgeModule( int index, out bool bContinue )
		{
			char[][] 		words;
			bool[char[]]	bAlreadyImported;

			foreach( CAnalyzerTreeNode t; importModules )
			{
				if( t.getLeafCount() )
				{
					char[] moduleName = t.getLeaf( 0 ).identifier;

					foreach( CAnalyzerTreeNode tt; _getRenamedImport() )
					{
						if( tt.identifier == moduleName )
							if( tt.typeIdentifier.length )
							{
								moduleName = tt.typeIdentifier;
								break;
							}
					}

					char[][] splitedModuleName = std.string.split( moduleName, "." );

					
					if( splitedModuleName.length == 1 )
					{
						if( word == moduleName )
						{
							list ~= moduleToAutoCShow( t );
							bModuleImportCall = true;
							if( currentWords.length == 1 ) return null;else list.length = 0;
						}
					}

					if( currentWords.length < splitedModuleName.length )
					{
						int j;
						for( j = 0; j < currentWords.length; ++ j )
						{
							if( currentWords[j] != splitedModuleName[j] ) break;
						}

						if( j == currentWords.length )
						{
							if( !( splitedModuleName[j] in bAlreadyImported ) )
							{
								words ~= splitedModuleName[j];
								bAlreadyImported[splitedModuleName[j]] = true;
							}	
						}
					}
					else
					{
						int j;
						for( j = 0; j < splitedModuleName.length; ++ j )
						{
							if( currentWords[j] != splitedModuleName[j] ) break;
						}

						//words.length = 0;
						if( currentWords.length == splitedModuleName.length )
						{
							if( j == splitedModuleName.length )
							{
								list ~= moduleToAutoCShow( t );
								return null;
							}
						}
						else if( currentWords.length > splitedModuleName.length )
						{
							if( index < splitedModuleName.length )
							{
								bContinue = true;
								continue;
							}
											
							if( j == splitedModuleName.length )
							{
								bModuleImportCall = false;
								CAnalyzerTreeNode[] _dummyClasses;
								CAnalyzerTreeNode treeNode = sAutoComplete.getMemberAnalyzerTreeNode( word, D_VARIABLE | D_UDTS | D_FUNCTION, t, _dummyClasses );
								bNotFriendClass = true;
								return _getType( treeNode );
							}
						}
					}
				}
			}
			
			
			if( words.length )
			{
				scope CCharsSort!( char[] ) sortList = new CCharsSort!( char[] )( words );
				words = sortList.pop();
				list = std.string.join( words, "?22 " ) ~ "?22";
				//if( index == 0 ) bContinue = true;
			}
			

			return null;
		}

		if( functionHeadNode )
		{
			/*
			// 看看currentWords是不是 D_ALIAS
			char[] joinWord = std.string.join( currentWords, "." );
			CAnalyzerTreeNode typeAlias = sAutoComplete.getAnalyzerTreeNode( joinWord, D_ALIAS, functionHeadNode, true );
			if( !typeAlias )
			{
				CAnalyzer[] dummyAnalyzers;
				typeAlias = sAutoComplete.getImport( joinWord, D_ALIAS, functionHeadNode, dummyAnalyzers );
			}
			if( typeAlias ) currentWords = std.string.split( typeAlias.typeIdentifier, "." );
			*/

			for( int i = 0; i < currentWords.length; ++ i )
			{
				word = _checkArrayOrFunction( currentWords[i] );
				if( !word.length ) return null;
				
				int DType;
				//if( bIsFunction ) DType = D_FUNCTION;else 
				DType = D_ALL - D_IMPORT - D_MAINROOT - D_MODULE - D_UNITTEST -D_UNKNOWN;

				baseClasses.length = 0;

				if( i == 0 )
				{	
					// 先找fileParser
					activeTreeNode = sAutoComplete.getAnalyzerTreeNode( word, DType, functionHeadNode, true );

					// 找function內的內容
					if( !activeTreeNode )
						activeTreeNode = _lookBLOCK( functionHeadNode ); // Not Cool........
					else
					{
						if( word == "this" ) activeTreeNode = null; // for class/interface pointer or ctor
					}

					
					// 找繼承的BaseClass
					if( !activeTreeNode )
					{
						CAnalyzerTreeNode rootNode = functionHeadNode.getRoot();
						CAnalyzerTreeNode fatherNode;
						
						while( rootNode )
						{
							if( rootNode.DType & ( D_CLASS | D_INTERFACE ) )
							{
								if( word == "this" )
								{
									activeTreeNode = rootNode;
									break;
								}
								else if( rootNode.baseClass.length )
								{
									fatherNode = rootNode;
									break;
								}
							}
							
							rootNode = rootNode.getRoot();
						}

						if( fatherNode )
						{
							baseClasses = sAutoComplete.getBaseClassNode( fatherNode );
							CAnalyzerTreeNode[] dummyClasses;
							
							foreach( CAnalyzerTreeNode t; baseClasses )
							{
								activeTreeNode = sAutoComplete.getMemberAnalyzerTreeNode( word, DType, t, dummyClasses );
								if( activeTreeNode )
								{
									//if( sAutoComplete.getAnalyzerTreeNode( t.identifier, D_CLASS | D_INTERFACE, functionHeadNode, true ) is null ) bNotFriendClass = true;
									break;
								}
							}
							baseClasses.length = 0;
						}
					}
					
					// 找import的模組
					if( !activeTreeNode )
					{
						CAnalyzerTreeNode[] dummyAnalyzers;
						activeTreeNode = sAutoComplete.getImport( word, DType, functionHeadNode, dummyAnalyzers );
						if( activeTreeNode ) bNotFriendClass = true;
					}

					// 找import的模組
					if( !activeTreeNode )
					{
						bool bContinue;
						activeTreeNode = sAutoComplete.getImport( word, DType, functionHeadNode, importModules, true );

						_judgeModule( i, bContinue );

						if( bContinue )
						{
							bModuleImportCall = true;
							continue;
						}
					}

					if( activeTreeNode ) 
						activeTreeNode = _getType( activeTreeNode );
					else
					{
						//MessageBox.showMsg("error = " ~ word );
						break;
					}
				}
				else // i > 0
				{
					list.length = 0;
					listToolTip.length = 0;
					activeTreeNode = sAutoComplete.getMemberAnalyzerTreeNode( word, DType, activeTreeNode, baseClasses );
					baseClasses.length = 0;
					activeTreeNode = _getType( activeTreeNode );

					if( !activeTreeNode )
					{
						if( bModuleImportCall )
						{
							bool bContinue;
							activeTreeNode = _judgeModule( i, bContinue );

							if( bContinue ) continue;
							if( !activeTreeNode ) break;
						}
						else
							continue;
					}
				}
			}

			return activeTreeNode;
		}
	}


	static char[] readHoverWord( Scintilla sc )
	{
		if ( sc.getLineCount() <= 2 ) return null;
		int pos =  sc.getCurrentPos();
		int endLine = sc.getLineCount();
		int endPos = sc.positionFromLine( endLine );
		char[] wordForward, wordBackward, word;
	
		char ch = sc.getCharAt( pos++ );
		wordForward ~= ch;

		while( !isWordBreak( ch ) )
		{
			ch = sc.getCharAt(pos++);
			wordForward ~= ch;
			if( pos >= endPos ) break;
		}
	
		pos = sc.getCurrentPos();
		ch 	= sc.getCharAt( --pos );
	
		while( !isWordBreak( ch ) )
		{
			ch = sc.getCharAt(pos--);
			wordBackward ~= ch;
			if( pos <= 0 ) break;
		}
		
		wordBackward.reverse;
	
		word = wordBackward ~ wordForward;
	
		if( isWordBreak( word[word.length - 1] ) ) word = word[0..word.length - 1];

		if( isWordBreak( word[0] ) ) word = word[1..word.length];
	
		return std.string.strip( word );
	}

	
	static char[] readHoverWord( Scintilla sc, int pos )
	{
		char[]		text;
		dchar[] 	word, oWord;
		dchar 		ch;

		while( pos > -1 )
		{
			ch = sc.getCharAt( pos );

			if( ch != '.' )
				if( isWordBreak( ch ) ) break;			

			-- pos;
			oWord ~= ch;
		}

		/+
		try
		{
			oWord.reverse;
			text = std.utf.toUTF8( oWord );
			std.utf.validate( text ); 		// 檢查是否為有效的 UTF8

			//MessageBox.showMessage( text );
		}
		catch
		{
		}
		+/


		// look back
		pos ++;
		int arraySignCount;
		
		do 
		{
			ch = sc.getCharAt( pos );

			if( ch == '[' )
				arraySignCount ++;
			else if( ch == ']' )
				arraySignCount --;
			else if( ch == ' ' )
			{
				if( arraySignCount == 0 ) break;
			}
			else if( ch != '.' )
			{
				if( isWordBreak( ch ) )	break;
			}

			word ~= ch;
			++ pos;
		}
		while( ch != '\0' )
		

		if( !word.length ) return null;

		try
		{
			text = std.utf.toUTF8( word );
			std.utf.validate( text ); 		// 檢查是否為有效的 UTF8

			return std.string.strip( text );
		}
		catch
		{
		}

		return null;
	}

	void performAbbreviationExpand(Scintilla sc) {}

	void performImportStart(Scintilla sc)
	{
		char[] list = sAutoComplete.importParser.initialImports();
		if( list.length ) sc.autoCShow( 0, list );
	}
	

	// functions from scintillautil
	void skipWhiteSpace( Scintilla sc, inout int pos , int direction = 0 /* 0 for backward, 1 for forward */ )
	{
		if( direction )
		{	
			while( sc.getCharAt( pos ) == ' ' || sc.getCharAt( pos ) == '\t' )
			{
				pos ++;
			}
			pos--;
		}
		else 
		{
			while( sc.getCharAt( pos ) == ' ' || sc.getCharAt( pos ) == '\t' )
			{
				pos --;
			}
			pos++;
		}
	}

	private char[][] readCurrentWholeWord( Scintilla sc )
	{
		char[] 	word;
		dchar[] dword;
		int 	pos = sc.getCurrentPos() - 2;
		dchar 	ch  = sc.getCharAt( pos );

		int		parenCount, hCount;
		bool 	bBlockCommet, bResetCommet;

		bool _wordBreak()
		{
			switch( ch )
			{
				case ';':
				case '}':
				case '{':
				case ':':
				case '\n':
				case '>':
				case '<':
				case '=':
					return true;
					break;

				case '[':
				case '(':
					parenCount --;
					if( parenCount < 0 ) return true;
					return false;
					break;
					
				case ']':
				case ')':
					parenCount ++;
					return false;
					break;

				case ',':
					if( parenCount == 0 ) return true;
					return false;
					break;

				case '/':
					char prevWord = sc.getCharAt( pos - 1 );
					if( prevWord == '*' || prevWord == '+' )
					{
						bBlockCommet = true;
						return false;
					}

					char nextWord = sc.getCharAt( pos + 1 );
					if( nextWord == '*' || nextWord == '+' ) 
						bResetCommet = true;
					else
					{
						if( parenCount == 0 ) return true;
					}
					
					return false;
					break;

				case '+':
				case '-':
				case '*':
					if( parenCount == 0 ) return true;else return false;
					break;
			
				default:
					return false;
					break;
			}
		}

		if( ch == '.' ) return null;

		while( !_wordBreak() )
		{
			if( parenCount == 0 )
			{
				if( !bBlockCommet )
				{
					if( ch == ' ' ||  ch == '\t' )
					{
						try
						{
							char[] w = std.utf.toUTF8( dword );
							std.utf.validate( w ); 		// 檢查是否為有效的 UTF8
							if( std.string.strip( w ).length ) break;
						}
						catch( Exception )
						{
							return null;
						}
					}
				}
			}
			
			if( !bBlockCommet ) dword ~= ch;
			
			if( bResetCommet ) bResetCommet = bBlockCommet = false;
				
			pos --;
			if( pos < 0 ) break;
			ch = sc.getCharAt( pos );
		}


		if( dword ) 
			dword.reverse;
		else
		{
			//sGUI.outputPanel.appendString( "Null Word!!\n" );
			return null;
		}


		try
		{
			word = std.utf.toUTF8( dword );
			std.utf.validate( word ); 		// 檢查是否為有效的 UTF8
		}
		catch( Exception )
		{
			return null;
		}
		
		word = std.string.removechars( word, " " );
		word = std.string.removechars( word, "\t" );
		word = std.string.removechars( word, "\r" );
		word = std.string.removechars( word, "\n" );

		// 得到字



		char[] 	ident, skipSign;
		int		countArraySign, countFunctionSign;
		// 去掉()及[]內的參數
		for( int i = 0; i < word.length; ++ i )
		{
			if( skipSign == "" )
			{
				if( word[i] == '(' ) skipSign = "(";
				if( word[i] == '[' ) skipSign = "[";

				if( word[i] == '=' ) ident = null;else ident ~= word[i];
			}else
			{
				if( skipSign == "[" )
				{
					if( word[i] == ']' )
					{
						if( countArraySign == 0 )
						{
							ident ~= ']';
							skipSign = "";
						}else
						{
							countArraySign --;
						}
					}else if( word[i] == '[' )
					{
						countArraySign ++;
					}
				}else if( skipSign == "(" )
				{
					if( word[i] == ')' )
					{
						if( countFunctionSign == 0 )
						{
							ident ~= ')';
							skipSign = "";
						}else
						{
							countFunctionSign --;
						}
					}else if( word[i] == '(' )
					{
						countFunctionSign ++;
					}
				}
			}
		}

		ident.reverse;
		word = null;
		bool bWriteable = true, bHadWord;
		
		for( int i = 0; i < ident.length; ++ i )
		{
			if( ident[i] == ')' )
			{
				if( bHadWord ) 
					bWriteable = false;
				else
					word ~= ident[i];
			}else if( ident[i] == '(' )
			{
				if( bWriteable ) word ~= ident[i];
			}else if( ident[i] == '.' )
			{
				word ~= ident[i];
				bWriteable = true;
				bHadWord   = false;
			}else
			{
				if( bWriteable ) 
				{
					word ~= ident[i];
					bHadWord = true;
				}
					
			}
		}
		word.reverse;

		//sGUI.outputPanel.appendString( "Fix WholeWord is >" ~ word ~ "<\n" );
		
		return std.string.split( word, "." );
	}


	void addAnalyzerNodeLive( Scintilla sc )
	{
		if( !sAutoComplete.fileParser ) return;
		
		CAnalyzerTreeNode headNode = searchFunctionHead( sc );//findFunctionHead( sc );

		if( !headNode ) return;

		char[]		text, oText;
		dchar[] 	word, oWord;
		int 		pos =  sc.getCurrentPos();
		int			oPos = pos - 1;
		dchar 		ch;

		// look back
		if( sc.getCharAt( pos ) == ';' )
		{
		}
		else if( sc.getCharAt( pos - 1 ) == ';' )
		{
			pos -= 1;
		}
		else
		{
			do 
			{
				ch = sc.getCharAt( pos );
				if( ch == ';' || ch == '}' || ch == '{' || ch == ':' || ch == '\n' ) break;
				++ pos;
			}
			while( ch != '\0' )
		}

		// look front
		bool bFrontSign;
		
		while( pos > 0 )
		{
			ch = sc.getCharAt( pos );

			if( ch == ';' || ch == '}' || ch == '{' || ch == ':' )
			{
				if( bFrontSign ) break;else bFrontSign = true;
			}

			if( ch != '\n' )
			{
				if( ch == '\t' && sc.getCharAt( pos - 1 ) == '\n' )
				{
				}
				else
				{
					word ~= ch;
					if( pos != oPos ) oWord ~= ch;
				}
			}

			-- pos;
		}

		if( !word.length ) return;
		if( word == oWord ) return;


		// 取得原來文字的node
		CAnalyzerTreeNode oAnalyzerNode;
		try
		{
			if( oWord.length )
			{
				oWord.reverse;
				oText = std.utf.toUTF8( oWord );
				std.utf.validate( oText ); 		// 檢查是否為有效的 UTF8

				oText = std.string.strip( oText );

				oAnalyzerNode = Analyzer.D.syntax.CoreAnalyzer.parseTextHSU( oText, null, false );
				if( oAnalyzerNode )
					if( oAnalyzerNode.getLeafCount() < 1 ) delete oAnalyzerNode;
			}
		}
		catch
		{
			if( oAnalyzerNode ) delete oAnalyzerNode;
		}


		CAnalyzerTreeNode liveAnalyzernNode;
		try
		{
			// 目前文字的node
			word.reverse;
			text = std.utf.toUTF8( word );
			std.utf.validate( text ); 		// 檢查是否為有效的 UTF8

			text = std.string.strip( text );

			liveAnalyzernNode = Analyzer.D.syntax.CoreAnalyzer.parseTextHSU( text, null, false );

			if( liveAnalyzernNode )
			{
				if( liveAnalyzernNode.getLeafCount() < 1 )
				{
					delete liveAnalyzernNode;
					return;
				}
			}
		
			
			CAnalyzerTreeNode activeTreeNode = headNode;

			// Nested Function
			int _checkExist( CAnalyzerTreeNode node )
			{
				for( int i = 0; i < activeTreeNode.getLeafCount(); ++ i )
				{
					if( activeTreeNode.DType & D_VARIABLE )
					{
						if( activeTreeNode.getLeaf( i ).identifier == node.identifier && 
							activeTreeNode.getLeaf( i ).DType == node.DType ) 
							return i;
					}
				}

				return -1;
			}

			// Nested Function
			void _dupTreeNode( CAnalyzerTreeNode treeNode )
			{
				foreach( CAnalyzerTreeNode t; treeNode.getAllLeaf() )
				{
					if( t.DType & D_VARIABLE )
					{
						activeTreeNode.addLeaf( t.prot, t.DType, t.identifier, t.typeIdentifier, sc.lineFromPosition( sc.getCurrentPos() ),
												t.parameterString, t.baseClass );
						
						//activeTreeNode = activeTreeNode.getLeaf( activeTreeNode.getLeafCount() - 1 );
						//_dupTreeNode( t );
						//activeTreeNode= activeTreeNode.getRoot();
					}
				}
			}


			// 有原來文字的Node刪除之
			if( oAnalyzerNode )
			{
				foreach( CAnalyzerTreeNode t; oAnalyzerNode.getAllLeaf() )
				{
					if( t.DType & D_VARIABLE )
					{
						int oldIndex =_checkExist( t );

						if( oldIndex >= 0 )
						{
							CAnalyzerTreeNode[] 	tempChildren;
							CAnalyzerTreeNode       delChild;

							for( int i = 0; i < activeTreeNode.getLeafCount(); ++ i )
							{
								if( i != oldIndex )	tempChildren ~= activeTreeNode.getLeaf( i );
							}

							CAnalyzerTreeNode delNode = activeTreeNode.getLeaf( oldIndex );
							delete delNode;

							activeTreeNode.passChildren( tempChildren );
						}
					}
				}
			}

			// 加入目前文字的Node
			_dupTreeNode( liveAnalyzernNode );		
		}
		catch
		{
			if( liveAnalyzernNode ) delete liveAnalyzernNode;
			// liveAnalyzernNode parse error!!
		}

		if( oAnalyzerNode ) delete oAnalyzerNode;
		if( liveAnalyzernNode ) delete liveAnalyzernNode;
	}

	

	static char[] readCurrentWord( Scintilla sc, bool skipOverWordBreaks = false, int shift = -1 )
	{
		dchar[] word;
		int 	pos =  sc.getCurrentPos() + shift;
		dchar 	ch = sc.getCharAt( pos );

		if( skipOverWordBreaks )
		{
			while( isWordBreak( ch ) ) 
				ch = sc.getCharAt( pos-- );

			pos++;
		}

		while( !isWordBreak( ch ) )
		{
			ch = sc.getCharAt( pos-- );
			word ~= ch;
			if( pos < 0 ) break;
		}

		if( word.length > 1 )
			word.reverse;
		else
			return null;
	
		if( isWordBreak( word[word.length - 1] ) ) word = word[0..word.length - 1 ];
		if( isWordBreak( word[0] ) ) word = word[1..word.length ];

		char[] ret;
  
		try
		{
			ret = std.utf.toUTF8( word );
			std.utf.validate( ret ); 		// 檢查是否為有效的 UTF8
		}
		catch( Exception )
		{
			ret = null;
		}

		return ret;
	}

	// 檢查型別 type
	private bool isBuiltInType( char[] type, inout char[] listStr )
	{
		if( !type.length ) return true;
		
		char[] integralList = "alignof init max min sizeof";
		char[] floatList = "alignof dig epsilon infinity init min min_10_exp min_exp mant_dig max max_10_exp max_exp nan sizeof";
		char[] arrayList = "dup length ptr reverse sizeof sort";
		
		// Nested Function
		char[] getList( char[] types )
		{
			if( types == "int" ) 
				return integralList.dup;
			else if ( types == "uint" )
				return integralList.dup;
			else if ( types == "bool" )
				return integralList.dup;
			else if( types == "byte" )
				return integralList.dup;
			else if( types == "ubyte" )
				return integralList.dup;
			else if( types == "short" )
				return integralList.dup;
			else if( types == "ushort" )
				return integralList.dup;
			else if ( types == "long" )
				return integralList.dup;
			else if ( types == "ulong" )
				return integralList.dup;
			else if ( types == "char" )
				return integralList.dup;
			else if( types == "wchar" )
				return integralList.dup;
			else if( types == "dchar" )
				return integralList.dup;
			else if ( types == "cent" )
				return floatList.dup;
			else if ( types == "ucent" )
				return floatList.dup;
			else if ( types == "float" )
				return floatList.dup;
			else if( types == "double" )
				return floatList.dup;
			else if( types == "real" )
				return floatList.dup;
			else if( types == "ifloat" )
				return floatList.dup;
			else if( types == "idouble" )
				return floatList.dup;
			else if( types == "ireal" )
				return floatList.dup;
			else if( types == "cfloat" )
				return floatList.dup;
			else if( types == "cdouble" )
				return floatList.dup;
			else if( types == "creal" )
				return floatList.dup;
			else
				return null;
		}

		char[][] 	noArrayType = std.string.split( type, "[" );
		char[] 		temp;

		if( noArrayType.length > 1 )
		{
			temp = getList( noArrayType[0] );
			if( temp.length )
			{
				listStr = arrayList.dup;
				listStr = std.string.replace( listStr, " ", "?21 " ) ~ "?21";
				return true;
			}
			else
			{
				listStr = null;
				return false;
			}
		}else
		{
			temp = getList( noArrayType[0] );
			if( temp.length )
			{
				listStr = temp;
				listStr = std.string.replace( listStr, " ", "?21 " ) ~ "?21";
				return true;
			}
			else
			{
				listStr = null;				
				return false;
			}
		}
	}



	static bool isWordBreak( char ch )
	{
		if ( ch == '.' || ch == ' ' || ch == '\t' || ch == ')' || ch == '('
			|| ch == '*' || ch == '+' || ch == '-' || ch == '/' || ch == '&'
			|| ch == ']' || ch == '[' || ch == '}' || ch == '\r' || ch == '\n'
			|| ch == ',' || ch == '=' || ch == ';' || ch == '!' ) return true;

		return false;
	}

	void performWordHover(Scintilla sc)
	{
	  // need to display this somewhere else besides callTips -- maybe a new control

	//   try {

	// 	  char [] word = readHoverWord(sc);
	// 	  if ( word.length )
	// 		{
	// 		  word.strip();
	// 		  SymbolListing [] listings = sAutoComplete.search(word);
	// 		  //MessageBox.showMsg(word);
	// 		  // TODO : make this smarter, instead of just choosing the first match
	// 		  if ( listings.length )
	// 		{
	// 		  SymbolListing l = listings[0];
			  
	// 		  char []  display = SymbolToChars(l.sym);
			  
	// 		  sc.callTipShow(sc.getCurrentPos(),display );

	// 		}
	// 		  //else sc.callTipCancel();
			  
			  
	// 		}
	//   }
	//   catch ( Exception e ) { 		  /* MessageBox.showMsg(e.toString() );*/ } 
	  
	}


	char[] readImportWord( Scintilla sc )
	{
		int 	pos = sc.getCurrentPos();
		char[] 	word;

		char ch = sc.getCharAt( --pos );

		while( ch != ' ' && ch != '\n' && ch != '\r' )
		{
			ch = sc.getCharAt( pos-- );
			word ~= ch;
			if ( pos < 0 ) break;
		}
		
		if( word.length > 1 ) word.reverse;
		
		if( word[$ - 1] == '.' ) word = word[0..$ - 1];

		return strip( word );
	}


	private char[] symbolsToAutoCShow( CAnalyzerTreeNode treeNode, bool bNotFriendClass, CAnalyzerTreeNode[] baseClasses  ) 
	{
		CAnalyzerTreeNode[] nodes;
		
		void _getName( CAnalyzerTreeNode treeNode, bool bNotFriendClass )
		{
			int DType = D_VARIABLE | D_UDTS | D_FUNCTION;
			
			foreach( CAnalyzerTreeNode t; treeNode.getAllLeaf())
			{
				if( t.DType & DType )
				{
					if( Globals.showAllMember )
						nodes ~= t;
					else
					{
						if( !bNotFriendClass )
							nodes ~= t;
						else
							if( !( t.prot & ( D_Private | D_Protected ) ) ) nodes ~= t;
					}
				}
			}
		}

		_getName( treeNode, bNotFriendClass );

		if( baseClasses.length )
		{
			foreach( CAnalyzerTreeNode t; baseClasses )
			{
				_getName( t, true );
			}
		}
		
		char[][] words = sAutoComplete.setMemberImage( nodes );
		char[] ret = std.string.join( words, " " );

		return ret;
	}	


	private char[] moduleToAutoCShow( CAnalyzerTreeNode treeNode ) 
	{
		CAnalyzerTreeNode[] nodes;

		void _getName( CAnalyzerTreeNode treeNode )
		{
			foreach( CAnalyzerTreeNode t; treeNode.getAllLeaf())
			{
				version( Windows )
				{
					if( t.DType & D_VERSION )
					{
						if( t.identifier == "Windows" || t.identifier == "Win32" ) _getName( t );
						continue;
					}
				}
				
				if( !( t.prot & ( D_Private | D_Protected ) ) )
				{
					if( t.DType & ( D_VARIABLE | D_UDTS | D_FUNCTION ) ) nodes ~= t;
				}
			}
		}

		_getName( treeNode );

		char[][] words = sAutoComplete.setMemberImage( nodes );
		char[] ret = std.string.join( words, " " );

		return ret;
	}


	static private CAnalyzerTreeNode searchFunctionHead( Scintilla sc )
	{
		if( !sAutoComplete.fileParser ) return null;
		
		bool 				bMatch;
		int					originPos = sc.getCurrentPos();
		int 				pos = originPos - 1;
		char 				ch 	= sc.getCharAt( pos );
		char[]				word, finalWord, paramWord;

		CAnalyzerTreeNode 	result;


		bool _isOperatorOverload( char[] s )
		{
			if( s == "opCall" || s == "opSlice" || s == "opSliceAssign" || s == "opAssign" ) 
				return true;
			else
				return false;
		}

		CAnalyzerTreeNode _getParam( int posLeftParen, int posRightParen, CAnalyzerTreeNode[] treeNodes )
		{
			if( !treeNodes.length ) return null;
			// If function overload......
			char[] paramWord;

			if( posLeftParen + 1 == posRightParen )
				paramWord = "";
			else
			{
				for( int i = posLeftParen + 1; i < posRightParen; ++ i )
					paramWord ~= sc.getCharAt( i );

				paramWord = std.string.removechars( paramWord, " " );
				paramWord = std.string.removechars( paramWord, "\t" );
				paramWord = std.string.removechars( paramWord, "\r" );
				paramWord = std.string.removechars( paramWord, "\n" );

				char[] temp;
				bool   bPass = true;
				foreach( char c; paramWord )
				{
					if( bPass )
						if( c == '=' ) bPass = false;else temp ~= c;
					else
					{
						if( c == ',' )
						{
							bPass = true;
							temp~= ',';
						}
					}
				}
				paramWord = temp;
			}

			foreach( CAnalyzerTreeNode t; treeNodes )
			{
				char[] nodeParamStr = std.string.removechars( t.parameterString, " " );
				if( paramWord == nodeParamStr )	return t;
			}

			return null;
		}
		

		CAnalyzerTreeNode _findAnalyzerNode( int posLeftParen, int posRightParen, int types = 0 )
		{
			int 	semiPos = posLeftParen - 1;
			char 	semiChar = sc.getCharAt( semiPos );
			char[] 	semiWord;
					
			while( semiChar != ';' &&  semiChar != '}' && semiChar != '{' && semiChar != ':' )
			{
				if( semiChar != '\n' && semiChar !='\t' &&  semiChar != '\r' ) 
					if( semiChar < 128 ) semiWord ~= semiChar;
				else
					semiWord ~= " ";
						
				semiPos --;
				if( semiPos < 0 ) break;
				semiChar = sc.getCharAt( semiPos );
			}

			char[][] splitSemiWord = splitBySpace( semiWord );
			if( splitSemiWord.length )
			{
				switch( types )
				{
					case 0: // find UDT head
						char[] parenWord = splitSemiWord[length - 1 ];
						if( parenWord[length - 1] == ')' ) return null;
						/+
						foreach( char[] ss; splitSemiWord )
						{
							sGUI.outputPanel.appendLine( ss );
						}
						+/
						for( int i = 0; i < splitSemiWord.length; ++ i )
						{
							char[] s = splitSemiWord[i];
							if( s == "class" || s == "interface" ||	s == "struct" || s == "union" || s == "enum" )
							{
								char[] udtName;
								
								if( i < splitSemiWord.length - 1 )
								{
									// 去掉繼承的字
									char[][] inheritWords = std.string.split( splitSemiWord[i + 1], ":" );
									udtName = inheritWords[0];
								}
								else
									return null;

								CAnalyzerTreeNode[] treeNodes = sAutoComplete.lookAnalyzerTree( udtName, D_UDTS, sAutoComplete.fileParser );
								if( treeNodes.length ) return treeNodes[0];else return null;
							}
						}
						break;
						
					case 1:
						char[] finalWord = splitSemiWord[length - 1];
						if( finalWord != "if" && finalWord != "while" && finalWord != "for" && finalWord != "foeach"
								&& finalWord != "else" && finalWord != "version" && finalWord != "catch" 
								&& finalWord != "switch" && finalWord != "with" )
						{
							// 過載運算子及建構子
							if( finalWord == "this" || finalWord == "~this" || _isOperatorOverload( finalWord ) )
							{
								// 繼續找
								CAnalyzerTreeNode thisResultNode;
								int methodPos = semiPos;
	
								while( semiPos >= 0 )
								{
									char c = sc.getCharAt( semiPos );
									if( c == '{' )
									{
										int matchBracePos = sc.braceMatch( semiPos );

										if( matchBracePos > 0 )
											if( matchBracePos > methodPos )
											{
												thisResultNode = _findAnalyzerNode( semiPos, 0, 0 );
												if( thisResultNode !is null ) break;
											}
									}
									semiPos --;
								}

								if( thisResultNode )
								{
									CAnalyzerTreeNode[] treeNodes ;
									if( _isOperatorOverload( finalWord ) )
										treeNodes = sAutoComplete.lookAnalyzerTree( finalWord, D_FUNCTION, thisResultNode );
									else 
										treeNodes = sAutoComplete.lookAnalyzerTree( finalWord, D_CTOR | D_DTOR, thisResultNode );
										
									return _getParam( posLeftParen, posRightParen, treeNodes );
								}
							}
							
							//sGUI.outputPanel.appendString( "Function word = >" ~ finalWord ~ "<\n" );
							CAnalyzerTreeNode[] treeNodes = sAutoComplete.lookAnalyzerTree( finalWord, D_FUNCTION | D_CTOR | D_DTOR, sAutoComplete.fileParser );
							if( treeNodes.length ) 
							{
								if( treeNodes.length == 1 )
									return treeNodes[0];
								else
								{
									// If function overload......
									CAnalyzerTreeNode t = _getParam( posLeftParen, posRightParen, treeNodes );
									if( t ) return t;
								}
							}
						}
						break;
						
					default:
						return null;
				}
			}
			return null;
		}


	
		while( !bMatch )
		{
			switch( ch )
			{
				case '{':
					int matchBracePos = sc.braceMatch( pos );

					if( matchBracePos >= 0 ) 
					{
						if( matchBracePos < originPos ) // Nested Function
						{
							word = null;
							break;
						}
					}

					CAnalyzerTreeNode t = _findAnalyzerNode( pos, 0, 0 );
					if( t )
						return t;
					else
					{
						if( !word.length ) word = "{";else word = null;
					}
					break;

				case ')':
					if( word == "{" )
					{
						word = "){";
						int matchPos = sc.braceMatch( pos );
						if( matchPos >= 0 && matchPos < pos )
						{
							CAnalyzerTreeNode t = _findAnalyzerNode( matchPos, pos, 1 );
							if( t )
								return t;
							else
							{
								pos = matchPos;
								word = null;
							}
						}
					}
					break;

				case ' ':
				case '\t':
				case '\n':
				case '\r':
					break;

				case ';':
				case '!':
					word = null;
					break;

				default:
					break;
			}

			pos --;

			if( pos < 0 ) return sAutoComplete.fileParser;

			ch = sc.getCharAt( pos );
		}

		return null;


		/*
		if( result ) 
			sGUI.outputPanel.appendString( "Function Head = >" ~ result.typeIdentifier ~ " " ~ result.identifier ~ "<\n" );
		else
			sGUI.outputPanel.appendString( "Function Head not MATCH!!!!!!!\n" );
		*/
	}


	static private char[][] splitBySpace( in char[] s, bool isReverseWord = true )
	{
		if( !s.length ) return null;
		
		char[][] results;
		char[] tempWord;
		int skipSpace;

		
		if( !isReverseWord ) s.reverse;
		
		s = std.string.strip( s );
		s.reverse;
		s = std.string.strip( s ) ~ " "; 

		foreach( char c; s )
		{
			if( c != ' ' && c != '\n' && c != '\t' && c != '\r' )
			{
				tempWord ~= c;
				if( c == '[' )
					skipSpace ++;
				else if( c == ']' )
					skipSpace --;
			}
			else
			{
				if( tempWord.length )
				{
					if( !skipSpace )
					{
						if( results.length )
						{
							char[] ss = results[length-1];
							if( ss[length-1] == ']' )
							{
								if( tempWord[0] == '[' )
								{
									tempWord = ss ~ tempWord;
									results.length = results.length - 1;
								}
							}
						}
								
						results ~= tempWord;
						tempWord = "";
					}
				}
				else
					tempWord = "";
			}
		}
		return results;
	}

} // end of class DStyle
